<!DOCTYPE html>
<html>

<head>
  <title>Quarkus - Using the REST Client</title>
  <script id="adobe_dtm" src="https://www.redhat.com/dtm.js" type="text/javascript"></script>
  <script src="/assets/javascript/highlight.pack.js" type="text/javascript"></script>
  <META HTTP-EQUIV='Content-Security-Policy' CONTENT="default-src 'none'; script-src 'self' 'unsafe-eval' 'sha256-ANpuoVzuSex6VhqpYgsG25OHWVA1I+F6aGU04LoI+5s=' 'sha256-ipy9P/3rZZW06mTLAR0EnXvxSNcnfSDPLDuh3kzbB1w=' js.bizographics.com https://www.redhat.com assets.adobedtm.com jsonip.com https://ajax.googleapis.com https://www.googletagmanager.com https://www.google-analytics.com https://use.fontawesome.com; style-src 'self' https://fonts.googleapis.com https://use.fontawesome.com; img-src 'self' *; media-src 'self' ; frame-src https://www.googletagmanager.com https://www.youtube.com; frame-ancestors 'none'; base-uri 'none'; object-src 'none'; form-action 'none'; font-src 'self' https://use.fontawesome.com https://fonts.gstatic.com;">
  <META HTTP-EQUIV='X-Frame-Options' CONTENT="DENY">
  <META HTTP-EQUIV='X-XSS-Protection' CONTENT="1; mode=block">
  <META HTTP-EQUIV='X-Content-Type-Options' CONTENT="nosniff">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Quarkus: Supersonic Subatomic Java">
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:site" content="@QuarkusIO"> 
  <meta name="twitter:creator" content="@QuarkusIO">
  <meta property="og:url" content="https://quarkus.io/guides/rest-client" />
  <meta property="og:title" content="Quarkus - Using the REST Client" />
  <meta property="og:description" content="Quarkus: Supersonic Subatomic Java" />
  <meta property="og:image" content="/assets/images/quarkus_card.png" />
  <link rel="canonical" href="https://quarkus.io/guides/rest-client">
  <link rel="shortcut icon" type="image/png" href="/favicon.ico" >
  <link rel="stylesheet" href="https://quarkus.io/guides/stylesheet/config.css" />
  <link rel="stylesheet" href="/assets/css/main.css" />
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
  <link rel="alternate" type="application/rss+xml"  href="https://quarkus.io/feed.xml" title="Quarkus">
  <script src="https://quarkus.io/assets/javascript/goan.js" type="text/javascript"></script>
  <script src="https://quarkus.io/assets/javascript/hl.js" type="text/javascript"></script>
</head>

<body class="guides">
  <!-- Google Tag Manager (noscript) -->
  <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NJWS5L"
  height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
  <!-- End Google Tag Manager (noscript) -->

  <div class="nav-wrapper">
  <div class="grid-wrapper">
    <div class="width-12-12">
      <input type="checkbox" id="checkbox" />
      <nav id="main-nav" class="main-nav">
  <div class="container">
    <div class="logo-wrapper">
      
        <a href="/"><img src="/assets/images/quarkus_logo_horizontal_rgb_600px_reverse.png" class="project-logo" title="Quarkus"></a>
      
    </div>
    <label class="nav-toggle" for="checkbox">
      <i class="fa fa-bars"></i>
    </label>
    <div id="menu" class="menu">
      <span>
        <a href="/get-started/" class="">Get Started</a>
      </span>
      <span>
        <a href="/guides/" class="active">Guides</a>
      </span>
      <span>
        <a href="/community/" class="">Community</a>
      </span>
      <span>
        <a href="/support/" class="">Support</a>
      </span>
      <span>
        <a href="/blog/" class="">Blog</a>
      </span>
      <span>
        <a href="https://code.quarkus.io" class="button-cta secondary white">Start Coding</a>
      </span>
    </div>
  </div>
      </nav>
    </div>
  </div>
</div>

  <div class="content">
    <div class="guide">
  <div class="width-12-12">
    <h1 class="text-caps">Quarkus - Using the REST Client</h1>
    <div class="hide-mobile toc"><ul class="sectlevel1">
<li><a href="#prerequisites">Prerequisites</a></li>
<li><a href="#solution">Solution</a></li>
<li><a href="#creating-the-maven-project">Creating the Maven project</a></li>
<li><a href="#setting-up-the-model">Setting up the model</a></li>
<li><a href="#create-the-interface">Create the interface</a></li>
<li><a href="#create-the-configuration">Create the configuration</a></li>
<li><a href="#update-the-jax-rs-resource">Update the JAX-RS resource</a></li>
<li><a href="#update-the-test">Update the test</a></li>
<li><a href="#async-support">Async Support</a></li>
<li><a href="#package-and-run-the-application">Package and run the application</a></li>
<li><a href="#using-a-mock-http-server-for-tests">Using a Mock HTTP Server for tests</a></li>
<li><a href="#further-reading">Further reading</a></li>
</ul></div>
    <div>
      <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This guide explains how to use the MicroProfile REST Client in order to interact with REST APIs
with very little effort.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
there is another guide if you need to write server <a href="rest-json">JSON REST APIs</a>.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="prerequisites"><a class="anchor" href="#prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="paragraph">
<p>To complete this guide, you need:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>less than 15 minutes</p>
</li>
<li>
<p>an IDE</p>
</li>
<li>
<p>JDK 1.8+ installed with <code>JAVA_HOME</code> configured appropriately</p>
</li>
<li>
<p>Apache Maven 3.6.2+</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="solution"><a class="anchor" href="#solution"></a>Solution</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We recommend that you follow the instructions in the next sections and create the application step by step.
However, you can go right to the completed example.</p>
</div>
<div class="paragraph">
<p>Clone the Git repository: <code>git clone <a href="https://github.com/quarkusio/quarkus-quickstarts.git" class="bare">https://github.com/quarkusio/quarkus-quickstarts.git</a></code>, or download an <a href="https://github.com/quarkusio/quarkus-quickstarts/archive/master.zip">archive</a>.</p>
</div>
<div class="paragraph">
<p>The solution is located in the <code>rest-client-quickstart</code> <a href="https://github.com/quarkusio/quarkus-quickstarts/tree/master/rest-client-quickstart">directory</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="creating-the-maven-project"><a class="anchor" href="#creating-the-maven-project"></a>Creating the Maven project</h2>
<div class="sectionbody">
<div class="paragraph">
<p>First, we need a new project. Create a new project with the following command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">mvn io.quarkus:quarkus-maven-plugin:1.7.0.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=rest-client-quickstart \
    -DclassName="org.acme.rest.client.CountriesResource" \
    -Dpath="/country" \
    -Dextensions="rest-client, resteasy-jsonb"
cd rest-client-quickstart</code></pre>
</div>
</div>
<div class="paragraph">
<p>This command generates the Maven project with a REST endpoint and imports the <code>rest-client</code> and <code>resteasy-jsonb</code> extensions.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If your application does not expose any JAX-RS endpoints (eg. a <a href="command-mode-reference">command mode application</a>), use the <code>rest-client-jsonb</code> or the <code>rest-client-jackson</code> extension instead.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If you already have your Quarkus project configured, you can add the <code>rest-client</code> and the <code>rest-client-jsonb</code> extensions
to your project by running the following command in your project base directory:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="bash" class="language-bash hljs">./mvnw quarkus:add-extension -Dextensions="rest-client,resteasy-jsonb"</code></pre>
</div>
</div>
<div class="paragraph">
<p>This will add the following to your <code>pom.xml</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="xml" class="language-xml hljs">&lt;dependency&gt;
    &lt;groupId&gt;io.quarkus&lt;/groupId&gt;
    &lt;artifactId&gt;quarkus-rest-client&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;io.quarkus&lt;/groupId&gt;
    &lt;artifactId&gt;quarkus-resteasy-jsonb&lt;/artifactId&gt;
&lt;/dependency&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="setting-up-the-model"><a class="anchor" href="#setting-up-the-model"></a>Setting up the model</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In this guide we will be demonstrating how to consume part of the REST API supplied by the <a href="https://restcountries.eu">restcountries.eu</a> service.
Our first order of business is to setup the model we will be using, in the form of a <code>Country</code> POJO.</p>
</div>
<div class="paragraph">
<p>Create a <code>src/main/java/org/acme/rest/client/Country.java</code> file and set the following content:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">package org.acme.rest.client;

import java.util.List;

public class Country {

    public String name;
    public String alpha2Code;
    public String capital;
    public List&lt;Currency&gt; currencies;

    public static class Currency {
        public String code;
        public String name;
        public String symbol;
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The model above is only a subset of the fields provided by the service, but it suffices for the purposes of this guide.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="create-the-interface"><a class="anchor" href="#create-the-interface"></a>Create the interface</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Using the MicroProfile REST Client is as simple as creating an interface using the proper JAX-RS and MicroProfile annotations. In our case the interface should be created at <code>src/main/java/org/acme/rest/client/CountriesService.java</code> and have the following content:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.annotations.jaxrs.PathParam;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.Set;

@Path("/v2")
@RegisterRestClient
public interface CountriesService {

    @GET
    @Path("/name/{name}")
    @Produces("application/json")
    Set&lt;Country&gt; getByName(@PathParam String name);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>getByName</code> method gives our code the ability to query a country by name from the REST Countries API. The client will handle all the networking and marshalling leaving our code clean of such technical details.</p>
</div>
<div class="paragraph">
<p>The purpose of the annotations in the code above is the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>@RegisterRestClient</code> allows Quarkus to know that this interface is meant to be available for
CDI injection as a REST Client</p>
</li>
<li>
<p><code>@Path</code>, <code>@GET</code> and <code>@PathParam</code> are the standard JAX-RS annotations used to define how to access the service</p>
</li>
<li>
<p><code>@Produces</code> defines the expected content-type</p>
</li>
</ul>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>While <code>@Consumes</code> and <code>@Produces</code> are optional as auto-negotiation is supported,
it is heavily recommended to annotate your endpoints with them to define precisely the expected content-types.</p>
</div>
<div class="paragraph">
<p>It will allow to narrow down the number of JAX-RS providers (which can be seen as converters) included in the native executable.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="create-the-configuration"><a class="anchor" href="#create-the-configuration"></a>Create the configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In order to determine the base URL to which REST calls will be made, the REST Client uses configuration from <code>application.properties</code>.
The name of the property needs to follow a certain convention which is best displayed in the following code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs"># Your configuration properties
org.acme.rest.client.CountriesService/mp-rest/url=https://restcountries.eu/rest # <i class="conum" data-value="1"></i><b>(1)</b>
org.acme.rest.client.CountriesService/mp-rest/scope=javax.inject.Singleton # <i class="conum" data-value="2"></i><b>(2)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Having this configuration means that all requests performed using <code>org.acme.rest.client.CountriesService</code> will use <code><a href="https://restcountries.eu/rest" class="bare">https://restcountries.eu/rest</a></code> as the base URL.
Using the configuration above, calling the <code>getByName</code> method of <code>CountriesService</code> with a value of <code>France</code> would result in an HTTP GET request being made to <code><a href="https://restcountries.eu/rest/v2/name/France" class="bare">https://restcountries.eu/rest/v2/name/France</a></code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Having this configuration means that the default scope of <code>org.acme.rest.client.CountriesService</code> will be <code>@Singleton</code>. Supported scope values are <code>@Singleton</code>, <code>@Dependent</code>, <code>@ApplicationScoped</code> and <code>@RequestScoped</code>. The default scope is <code>@Dependent</code>.
The default scope can also be defined on the interface.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Note that <code>org.acme.rest.client.CountriesService</code> <em>must</em> match the fully qualified name of the <code>CountriesService</code> interface we created in the previous section.</p>
</div>
<div class="paragraph">
<p>To facilitate the configuration, you can use the <code>@RegisterRestClient</code> <code>configKey</code> property that allows to use another configuration root than the fully qualified name of your interface.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">@RegisterRestClient(configKey="country-api")
public interface CountriesService {
    [...]
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="properties" class="language-properties hljs"># Your configuration properties
country-api/mp-rest/url=https://restcountries.eu/rest #
country-api/mp-rest/scope=javax.inject.Singleton # /</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="update-the-jax-rs-resource"><a class="anchor" href="#update-the-jax-rs-resource"></a>Update the JAX-RS resource</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Open the <code>src/main/java/org/acme/rest/client/CountriesResource.java</code> file and update it with the following content:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.resteasy.annotations.jaxrs.PathParam;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.Set;

@Path("/country")
public class CountriesResource {

    @Inject
    @RestClient
    CountriesService countriesService;


    @GET
    @Path("/name/{name}")
    @Produces(MediaType.APPLICATION_JSON)
    public Set&lt;Country&gt; name(@PathParam String name) {
        return countriesService.getByName(name);
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that in addition to the standard CDI <code>@Inject</code> annotation, we also need to use the MicroProfile <code>@RestClient</code> annotation to inject <code>CountriesService</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="update-the-test"><a class="anchor" href="#update-the-test"></a>Update the test</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We also need to update the functional test to reflect the changes made to the endpoint.
Edit the <code>src/test/java/org/acme/rest/client/CountriesResourceTest.java</code> file and change the content of the <code>testCountryNameEndpoint</code> method to:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">package org.acme.rest.client;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class CountriesResourceTest {

    @Test
    public void testCountryNameEndpoint() {
        given()
          .when().get("/country/name/greece")
          .then()
             .statusCode(200)
             .body("$.size()", is(1),
                     "[0].alpha2Code", is("GR"),
                     "[0].capital", is("Athens"),
                     "[0].currencies.size()", is(1),
                     "[0].currencies[0].name", is("Euro")
             );
    }

}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The code above uses <a href="http://rest-assured.io/">REST Assured</a>'s <a href="https://github.com/rest-assured/rest-assured/wiki/GettingStarted#jsonpath">json-path</a> capabilities.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="async-support"><a class="anchor" href="#async-support"></a>Async Support</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The rest client supports asynchronous rest calls.
Async support comes in 2 flavors: you can return a <code>CompletionStage</code> or a <code>Uni</code> (requires the <code>quarkus-resteasy-mutiny</code> extension).
Let&#8217;s see it in action by adding a <code>getByNameAsync</code> method in our <code>CountriesService</code> REST interface. The code should look like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.annotations.jaxrs.PathParam;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.concurrent.CompletionStage;
import java.util.Set;

@Path("/v2")
@RegisterRestClient
public interface CountriesService {

    @GET
    @Path("/name/{name}")
    @Produces("application/json")
    Set&lt;Country&gt; getByName(@PathParam String name);

    @GET
    @Path("/name/{name}")
    @Produces("application/json")
    CompletionStage&lt;Set&lt;Country&gt;&gt; getByNameAsync(@PathParam String name);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Open the <code>src/main/java/org/acme/rest/client/CountriesResource.java</code> file and update it with the following content:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.resteasy.annotations.jaxrs.PathParam;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.concurrent.CompletionStage;
import java.util.Set;

@Path("/country")
public class CountriesResource {

    @Inject
    @RestClient
    CountriesService countriesService;


    @GET
    @Path("/name/{name}")
    @Produces(MediaType.APPLICATION_JSON)
    public Set&lt;Country&gt; name(@PathParam String name) {
        return countriesService.getByName(name);
    }

    @GET
    @Path("/name-async/{name}")
    @Produces(MediaType.APPLICATION_JSON)
    public CompletionStage&lt;Set&lt;Country&gt;&gt; nameAsync(@PathParam String name) {
        return countriesService.getByNameAsync(name);
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>To test asynchronous methods, add the test method below in <code>CountriesResourceTest</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">@Test
public void testCountryNameAsyncEndpoint() {
    given()
    .when().get("/country/name-async/greece")
    .then()
        .statusCode(200)
        .body("$.size()", is(1),
             "[0].alpha2Code", is("GR"),
             "[0].capital", is("Athens"),
             "[0].currencies.size()", is(1),
             "[0].currencies[0].name", is("Euro")
        );
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Uni</code> version is very similar:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.annotations.jaxrs.PathParam;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.concurrent.CompletionStage;
import java.util.Set;

@Path("/v2")
@RegisterRestClient
public interface CountriesService {

    // ...

    @GET
    @Path("/name/{name}")
    @Produces("application/json")
    Uni&lt;Set&lt;Country&gt;&gt; getByNameAsUni(@PathParam String name);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>CountriesResource</code> becomes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.resteasy.annotations.jaxrs.PathParam;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.concurrent.CompletionStage;
import java.util.Set;

@Path("/country")
public class CountriesResource {

    @Inject
    @RestClient
    CountriesService countriesService;


    // ...

    @GET
    @Path("/name-uni/{name}")
    @Produces(MediaType.APPLICATION_JSON)
    public Uni&lt;Set&lt;Country&gt;&gt; nameAsync(@PathParam String name) {
        return countriesService.getByNameAsUni(name);
    }
}</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Mutiny</div>
<div class="paragraph">
<p>The previous snippet uses Mutiny reactive types, if you&#8217;re not familiar with them, read the <a href="getting-started-reactive#mutiny">Getting Started with Reactive guide</a> first.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>When returning a <code>Uni</code>, every <em>subscription</em> invokes the remote service.
It means you can re-send the request by re-subscribing on the <code>Uni</code>, or use a <code>retry</code> as follow:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">@Inject @RestClient CountriesResource service;

// ...

service.nameAsync("Greece")
   .onFailure().retry().atMost(10);</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you use a <code>CompletionStage</code>, you would need to call the service&#8217;s method to retry.
This difference comes from the laziness aspect of Mutiny and its subscription protocol.
More details about this can be found in <a href="https://smallrye.io/smallrye-mutiny/#_uni_and_multi">the Mutiny documentation</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="package-and-run-the-application"><a class="anchor" href="#package-and-run-the-application"></a>Package and run the application</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Run the application with: <code>./mvnw compile quarkus:dev</code>.
Open your browser to <a href="http://localhost:8080/country/name/greece" class="bare">http://localhost:8080/country/name/greece</a>.</p>
</div>
<div class="paragraph">
<p>You should see a JSON object containing some basic information about Greece.</p>
</div>
<div class="paragraph">
<p>As usual, the application can be packaged using <code>./mvnw clean package</code> and executed using the <code>-runner.jar</code> file.
You can also generate the native executable with <code>./mvnw clean package -Pnative</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="using-a-mock-http-server-for-tests"><a class="anchor" href="#using-a-mock-http-server-for-tests"></a>Using a Mock HTTP Server for tests</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Setting up a mock HTTP server, against which tests are run, is a common testing pattern.
Examples of such servers are <a href="http://wiremock.org/">Wiremock</a> and <a href="https://docs.hoverfly.io/projects/hoverfly-java/en/latest/index.html">Hoverfly</a>.
In this section we&#8217;ll demonstrate how Wiremock can be leveraged for testing the <code>CountriesService</code> which was developed above.</p>
</div>
<div class="paragraph">
<p>First of all, Wiremock needs to be added as a test dependency. For a Maven project that would happen like so:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="xml" class="language-xml hljs">&lt;dependency&gt;
    &lt;groupId&gt;com.github.tomakehurst&lt;/groupId&gt;
    &lt;artifactId&gt;wiremock-jre8&lt;/artifactId&gt;
    &lt;scope&gt;test&lt;/scope&gt;
    &lt;version&gt;${wiremock.version}&lt;/version&gt; <i class="conum" data-value="1"></i><b>(1)</b>
&lt;/dependency&gt;</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Use a proper Wiremock version. All available versions can be found <a href="https://search.maven.org/artifact/com.github.tomakehurst/wiremock-jre8">here</a>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In Quarkus tests when some service needs to be started before the Quarkus tests are ran, we utilize the <code>@io.quarkus.test.common.QuarkusTestResource</code>
annotation to specify a <code>io.quarkus.test.common.QuarkusTestResourceLifecycleManager</code> which can start the service and supply configuration
values that Quarkus will use.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>For more details about <code>@QuarkusTestResource</code> refer to  <a href="getting-started-testing#quarkus-test-resource">this part of the documentation</a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Let&#8217;s create an implementation of <code>QuarkusTestResourceLifecycleManager</code> called <code>WiremockCountries</code> like so:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">package org.acme.rest.client;

import java.util.Collections;
import java.util.Map;

import com.github.tomakehurst.wiremock.WireMockServer;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

import static com.github.tomakehurst.wiremock.client.WireMock.*; <i class="conum" data-value="1"></i><b>(1)</b>

public class WiremockCountries implements QuarkusTestResourceLifecycleManager {  <i class="conum" data-value="2"></i><b>(2)</b>

	private WireMockServer wireMockServer;

	@Override
	public Map&lt;String, String&gt; start() {
		wireMockServer = new WireMockServer();
		wireMockServer.start(); <i class="conum" data-value="3"></i><b>(3)</b>

		stubFor(get(urlEqualTo("/v2/name/GR"))   <i class="conum" data-value="4"></i><b>(4)</b>
				.willReturn(aResponse()
						.withHeader("Content-Type", "application/json")
						.withBody(
                        "[{" +
                        "\"name\": \"Ελλάδα\"," +
                        "\"capital\": \"Αθήνα\"" +
                        "}]"
						)));

		stubFor(get(urlMatching(".*")).atPriority(10).willReturn(aResponse().proxiedFrom("https://restcountries.eu/rest")));   <i class="conum" data-value="5"></i><b>(5)</b>

		return Collections.singletonMap("org.acme.getting.started.country.CountriesService/mp-rest/url", wireMockServer.baseUrl()); <i class="conum" data-value="6"></i><b>(6)</b>
	}

	@Override
	public void stop() {
		if (null != wireMockServer) {
			wireMockServer.stop();  <i class="conum" data-value="7"></i><b>(7)</b>
		}
	}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Statically importing the methods in the Wiremock package makes it easier to read the test.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The <code>start</code> method is invoked by Quarkus before any test is run and returns a <code>Map</code> of configuration properties that apply during the test execution.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Launch Wiremock.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Configure Wiremock to stub the calls to <code>/v2/name/GR</code> by returning a specific canned response.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>All HTTP calls that have not been stubbed are handled by calling the real service. This is done for demonstration purposes, as it is not something that would usually happen in a real test.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>As the <code>start</code> method returns configuration that applies for tests, we set the rest-client property that controls the base URL which is used by the implementation
of <code>CountriesService</code> to the base URL where Wiremock is listening for incoming requests.</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>When all tests have finished, shutdown Wiremock.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>CountriesResourceTest</code> test class needs to be annotated like so:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">@QuarkusTest
@QuarkusTestResource(WiremockCountries.class)
public class CountriesResourceTest {

}</code></pre>
</div>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
<div class="paragraph">
<p><code>@QuarkusTestResource</code> applies to all tests, not just <code>CountriesResourceTest</code>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="further-reading"><a class="anchor" href="#further-reading"></a>Further reading</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://download.eclipse.org/microprofile/microprofile-rest-client-1.2.1/microprofile-rest-client-1.2.1.html">MicroProfile Rest Client specification</a></p>
</li>
</ul>
</div>
</div>
</div>
    </div>
  </div>
</div>

  </div>

  <div class="content project-footer">
  <div class="footer-section">
    <div class="logo-wrapper">
      <a href="/"><img src="/assets/images/quarkus_logo_horizontal_rgb_reverse.svg" class="project-logo" title="Quarkus"></a>
    </div>
  </div>
  <div class="grid-wrapper">
    <p class="grid__item width-3-12">Quarkus is open. All dependencies of this project are available under the <a href='https://www.apache.org/licenses/LICENSE-2.0' target='_blank'>Apache Software License 2.0</a> or compatible license.<br /><br />This website was built with <a href='https://jekyllrb.com/' target='_blank'>Jekyll</a>, is hosted on <a href='https://pages.github.com/' target='_blank'>Github Pages</a> and is completely open source. If you want to make it better, <a href='https://github.com/quarkusio/quarkusio.github.io' target='_blank'>fork the website</a> and show us what you’ve got.</p>

    
      <div class="width-1-12 project-links">
        <span>Navigation</span>
        <ul class="footer-links width-1-12">
          
            <li><a href="/">Home</a></li>
          
            <li><a href="/guides">Guides</a></li>
          
            <li><a href="/community/#contributing">Contribute</a></li>
          
            <li><a href="/faq">FAQ</a></li>
          
            <li><a href="/get-started">Get Started</a></li>
          
        </ul>
      </div>
    
      <div class="width-1-12 project-links">
        <span>Contribute</span>
        <ul class="footer-links width-1-12">
          
            <li><a href="https://twitter.com/quarkusio">Follow us</a></li>
          
            <li><a href="https://github.com/quarkusio">GitHub</a></li>
          
            <li><a href="/security">Security&nbsp;policy</a></li>
          
        </ul>
      </div>
    
      <div class="width-1-12 project-links">
        <span>Get Help</span>
        <ul class="footer-links width-1-12">
          
            <li><a href="https://groups.google.com/forum/#!forum/quarkus-dev">Forums</a></li>
          
            <li><a href="https://quarkusio.zulipchat.com">Chatroom</a></li>
          
        </ul>
      </div>
    

    
      <div class="width-3-12 more-links">
        <span>Quarkus is made of community projects</span>
        <ul class="footer-links">
          
            <li><a href="https://vertx.io/" target="_blank">Eclipse Vert.x</a></li>
          
            <li><a href="https://microprofile.io" target="_blank">Eclipse MicroProfile</a></li>
          
            <li><a href="https://hibernate.org" target="_blank">Hibernate</a></li>
          
            <li><a href="https://netty.io" target="_blank">Netty</a></li>
          
            <li><a href="https://resteasy.github.io" target="_blank">RESTEasy</a></li>
          
            <li><a href="https://camel.apache.org" target="_blank">Apache Camel</a></li>
          
            <li><a href="https://code.quarkus.io/" target="_blank">And many more...</a></li>
          
        </ul>
      </div>
    
  </div>
</div>
  <div class="content redhat-footer">
  <div class="grid-wrapper">
    <span class="licence">
      <i class="fab fa-creative-commons"></i><i class="fab fa-creative-commons-by"></i> <a href="https://creativecommons.org/licenses/by/3.0/" target="_blank">CC by 3.0</a> | <a href="https://www.redhat.com/en/about/privacy-policy">Privacy Policy</a>
    </span>
    <span class="redhat">
      Sponsored by
    </span>
    <span class="redhat-logo">
      <a href="https://www.redhat.com/" target="_blank"><img src="/assets/images/redhat_reversed.svg"></a>
    </span>
  </div>
</div>


  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" integrity="sha384-8gBf6Y4YYq7Jx97PIqmTwLPin4hxIzQw5aDmUg/DDhul9fFpbbLcLh3nTIIDJKhx" crossorigin="anonymous"></script>
  <script type="text/javascript" src="/assets/javascript/mobile-nav.js"></script>
  <script type="text/javascript" src="/assets/javascript/scroll-down.js"></script>
  <script src="/assets/javascript/satellite.js" type="text/javascript"></script>
  <script src="https://quarkus.io/guides/javascript/config.js" type="text/javascript"></script>
  <script src="/assets/javascript/search-filter.js" type="text/javascript"></script>
  <script src="/assets/javascript/back-to-top.js" type="text/javascript"></script>
</body>

</html>
